package com.weimob.mcloud.wechatwork.customer.job;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.weimob.elasticjob.annotation.ElasticJob;
import com.weimob.elasticjob.executor.context.ExecutorContext;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.CustomerEmployeeRelation;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.entity.retry.CustomerMsgRetry;
import com.weimob.mcloud.wechatwork.core.enums.customer.MsgRetryTypeEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.MsgStatusRetryEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.core.service.customer.request.RetryMsgScrollRequest;
import com.weimob.mcloud.wechatwork.customer.constant.RedisLockConstant;
import com.weimob.mcloud.wechatwork.customer.domain.ExternalUserChangeInfo;
import com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser.AddCorpExternaluserHandler;
import com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser.AddCorpExternaluserSecondHandler;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BasicInfo;
import com.weimob.mcloud.wechatwork.customer.third.PrivateSphereThird;
import com.weimob.mcloud.wechatwork.customer.third.customer.CustomerThird;
import com.weimob.soa.common.utils.SoaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author yuanhao
 * @date 2022/12/22 16:38
 */
@Slf4j
@Component
public class AddExternalUserRetryJob {

    @Reference
    private CustomerService customerService;

    @Autowired
    private PrivateSphereThird privateSphereThird;

    @Autowired
    private CustomerThird customerThird;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${scroll.pagesize:20}")
    private Integer scrollPageSize;

    @Autowired
    private AddCorpExternaluserHandler addCorpExternaluserHandler;

    @Autowired
    private AddCorpExternaluserSecondHandler addCorpExternaluserSecondHandler;

    /**
     * 消息重试job
     *
     * @param executorContext
     */
    @ElasticJob(name = "addExternalUserRetryJob", cron = "0 0/30 * * * ?")
    public void addExternalUserRetryJob(ExecutorContext executorContext) {
        //滚动查询db为处理的数据
        List<CustomerMsgRetry> list;
        int cycleTimes = 0;
        Long scrollId = null;
        do {
            cycleTimes++;
            //滚动抽取
            list = scrollQueryRetryData(scrollId);
            //业务处理
            for (CustomerMsgRetry customerMsgRetry : list) {
                try {
                    scrollId = customerMsgRetry.getId();
                    bizHandler(customerMsgRetry);
                } catch (Exception e) {
                    log.error("addExternalUserRetryJob 执行失败，customerMsgRetry：{}，e", JSON.toJSON(customerMsgRetry), e);
                }
            }

        } while (CollectionUtils.isNotEmpty(list) && cycleTimes < 10000);
    }


    /**
     * 逻辑处理
     *
     * @param customerMsgRetry customerMsgRetry
     */
    public void bizHandler(CustomerMsgRetry customerMsgRetry) {
        String msgJson = customerMsgRetry.getMsgJson();
        ExternalUserChangeInfo externalUserChangeInfo = JSON.parseObject(msgJson, ExternalUserChangeInfo.class);

        //记录当前id的重试次数
        Long id = customerMsgRetry.getId();
        String key = RedisLockConstant.ADD_EXTERNAL_USER_RETRY + id;
        Long currentRetryCount = redisTemplate.opsForValue().increment(key, 1);
        redisTemplate.expire(key, 1, TimeUnit.DAYS);

        //先判断wid是否生成
        String corpId = externalUserChangeInfo.getToUserName();
        String externalUserId = externalUserChangeInfo.getExternalUserID();
        Long bosId = externalUserChangeInfo.getBosId();
        Long superWid = null;
        try {
            BasicInfo basicInfo = new BasicInfo();
            basicInfo.setCorpId(corpId);
            basicInfo.setBosId(bosId);
            PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, Boolean.TRUE);
            superWid = customerThird.getSuperWid(privateSphere.getBosId(), externalUserId, corpId);
        } catch (Exception e) {
            log.error("AddExternalUserRetryJob.bizHandler,查询私域或者获取wid报错 error", e);
        }

        Integer retryCount = customerMsgRetry.getRetryCount();
        if (Objects.isNull(superWid)) {
            log.warn("addExternalUserRetryJob wid is null，externalUserId:{} 未换取到wid", externalUserId);
            //1.超过重试次数则去更新db状态
            boolean flag = Objects.nonNull(currentRetryCount) && Objects.nonNull(retryCount) && (currentRetryCount > retryCount);
            if (flag) {
                customerMsgRetry.setAlreadyRetryCount(currentRetryCount.intValue());
                customerMsgRetry.setMsgStatus(MsgStatusRetryEnum.FAILED.getCode());
                customerMsgRetry.setFailedReason("wid任务重试次数超限，仍未获取到");
                updateRetryRecord(customerMsgRetry);
                redisTemplate.delete(key);
            }
            return;
        }

        try {
            //正常执行业务
            addCorpExternaluserHandler.handleCorpExternalUser(externalUserChangeInfo);
            customerMsgRetry.setMsgStatus(MsgStatusRetryEnum.SUCCESS.getCode());
            customerMsgRetry.setAlreadyRetryCount(Objects.nonNull(currentRetryCount) ? currentRetryCount.intValue() : 0);
            updateRetryRecord(customerMsgRetry);
        } catch (Exception e) {
            log.error("AddExternalUserRetryJob.handleCorpExternalUser error:", e);
            customerMsgRetry.setMsgStatus(MsgStatusRetryEnum.FAILED.getCode());
            customerMsgRetry.setFailedReason("wid重试执行报错," + e.getMessage());
            updateRetryRecord(customerMsgRetry);
        }
    }


    /**
     * 滚动查询
     *
     * @param scrollId scrollId
     * @return
     */
    public List<CustomerMsgRetry> scrollQueryRetryData(Long scrollId) {
        SingleRequest<RetryMsgScrollRequest> singleRequest = new SingleRequest<>();
        RetryMsgScrollRequest scrollRequest = new RetryMsgScrollRequest();
        scrollRequest.setLimitSize(scrollPageSize);
        scrollRequest.setMsgStatus(MsgStatusRetryEnum.PENDING.getCode());
        scrollRequest.setMsgType(MsgRetryTypeEnum.ADD_EXTERNAL_USER.getCode());
        scrollRequest.setScrollId(scrollId);

        singleRequest.setData(scrollRequest);
        try {
            return SoaUtil.unpack(customerService.scrollRetryMsg(singleRequest));
        } catch (Exception e) {
            log.error("scrollQueryRetryData error", e);
            return Collections.emptyList();
        }
    }


    /**
     * 更新失败的消息的状态
     *
     * @param customerMsgRetry
     */
    public void updateRetryRecord(CustomerMsgRetry customerMsgRetry) {
        try {
            SingleRequest<CustomerMsgRetry> singleRequest = new SingleRequest<>();
            singleRequest.setData(customerMsgRetry);
            customerService.saveUpdateRetryMsg(singleRequest);
        } catch (Exception e) {
            log.error("更新客户重试表失败，updateRetryRecord failed,error", e);
        }
    }


    /**
     * 删除重试成功的消息 job
     * 从1号开始，每30天执行一次
     */
    @ElasticJob(name = "delRetryMsgJob", cron = "0 0 0 1/30 * ? ")
    public void delRetryMsgJob(ExecutorContext executorContext) {
        try {
            Map<String, String> map = executorContext.getTriggerCustomParameter();
            log.info("delRetryMsgJob start,param:{}", JSON.toJSONString(map));
            //msgStatus支持传参
            Integer msgStatus = MsgStatusRetryEnum.SUCCESS.getCode();
            if (MapUtils.isNotEmpty(map)) {
                String msgStatusReq = map.get("msgStatus");
                if (StringUtils.isNotBlank(msgStatusReq)) {
                    msgStatus = Integer.valueOf(msgStatusReq);
                }
            }
            SingleRequest<CustomerMsgRetry> singleRequest = new SingleRequest<>();
            CustomerMsgRetry customerMsgRetry = new CustomerMsgRetry();
            customerMsgRetry.setMsgStatus(msgStatus);

            Date date = new Date();
            Date endDate = DateUtils.addDays(date, -30);
            Date startDate = DateUtils.addDays(endDate, -30);

            singleRequest.setDateRangeBegin(startDate);
            singleRequest.setDateRangeEnd(endDate);
            singleRequest.setData(customerMsgRetry);
            //调用core执行清理sql
            log.info("delRetryMsgJob.deleteByMsgStatus param :{}", JSON.toJSONString(singleRequest));
            customerService.deleteByMsgStatus(singleRequest);
        } catch (Exception e) {
            log.error("清理客户重试表失败，delRetryMsgJob failed,error", e);
        }

    }


    /**
     * 更新关系表状态 job
     */
    @ElasticJob(name = "updateCustomerRelation")
    public void updateCustomerRelation(ExecutorContext executorContext) {
        try {
            Map<String, String> map = executorContext.getTriggerCustomParameter();

            //条件
            String corpId = map.get("corpId");
            String employeeId = map.get("employeeId");
            String customerId = map.get("customerId");
            //变更项
            String loseType = map.get("loseType");
            String friended = map.get("friended");
            //为了通知客搜
            String wid = map.get("wid");
            if (StringUtils.isBlank(corpId)) {
                log.error("updateCustomerRelation corpId is null");
                return;
            }
            if (StringUtils.isBlank(employeeId)) {
                log.error("updateCustomerRelation employeeId is null");
                return;
            }
            if (StringUtils.isBlank(customerId)) {
                log.error("updateCustomerRelation customerId is null");
                return;
            }
            if (StringUtils.isBlank(loseType)) {
                log.error("updateCustomerRelation loseType is null");
                return;
            }
            if (StringUtils.isBlank(friended)) {
                log.error("updateCustomerRelation friended is null");
                return;
            }
            if (StringUtils.isBlank(wid)) {
                log.error("updateCustomerRelation wid is null");
                return;
            }

            CustomerEmployeeRelation customerEmployeeRelation = new CustomerEmployeeRelation();
            customerEmployeeRelation.setCustomerId(customerId);
            customerEmployeeRelation.setLoseType(Integer.valueOf(loseType));
            customerEmployeeRelation.setCorpId(corpId);
            customerEmployeeRelation.setFriended(BooleanUtils.toBoolean(friended));

            Employee employee = new Employee();
            employee.setId(employeeId);
            customerEmployeeRelation.setEmployee(employee);

            BasicInfo basicInfo = new BasicInfo();
            basicInfo.setCorpId(corpId);

            PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, Boolean.TRUE);

            customerService.updateCustomerEmployeeRelation(customerEmployeeRelation);

            addCorpExternaluserSecondHandler.updateCustomerSearchHisMsg(Long.valueOf(wid), privateSphere.getBosId(), privateSphere.getProductInstanceId(), privateSphere.getProductId());

        } catch (Exception e) {
            log.error("更新客户关系数据，updateCustomerRelation failed,error", e);
        }
    }
}
